use std::{
    error::Error, fmt::{Display, Formatter}, hash::Hash, ops::{Add, Sub}, str::FromStr, sync::LazyLock, time::{Duration, SystemTime}
};
use serde::{
    Serialize, Deserialize, Serializer, Deserializer,
    de::{Visitor, Unexpected},
};
use time::{
    error::Format, format_description::FormatItem, formatting::Formattable,
    macros, parsing::Parsable, Date, OffsetDateTime, PrimitiveDateTime, Time,
    UtcOffset
};
pub use time::error::Parse as TimeParseError;

pub const DATETIME_FORMAT: &[FormatItem] = macros::format_description!("[year]-[month]-[day] [hour]:[minute]:[second]");
pub static LOCAL_OFFSET: LazyLock<UtcOffset> = LazyLock::new(|| UtcOffset::local_offset_at(OffsetDateTime::UNIX_EPOCH).unwrap());

fn parse_datetime(input: &str) -> Result<OffsetDateTime, TimeParseError> {
    let t = PrimitiveDateTime::parse(input, DATETIME_FORMAT)?;
    Ok(t.assume_offset(LOCAL_OFFSET.clone()))
}


#[derive(Clone, Debug, PartialEq, Eq)]
pub struct LocalDateTime(OffsetDateTime);

pub type LocalDate = Date;
pub type LocalTime = Time;

impl LocalDateTime {
    /// 获取当前本地时间
    pub fn now() -> Self {
        Self(OffsetDateTime::now_local().unwrap())
    }

    /// 使用unix时间戳创建一个本地时间
    pub fn from_unix_timestamp(timestamp: i64) -> Self {
        Self(OffsetDateTime::from_unix_timestamp(timestamp).unwrap().to_offset(LOCAL_OFFSET.clone()))
    }

    /// 本地时间转换为unix时间戳
    pub fn timestamp(&self) -> i64 {
        self.0.unix_timestamp()
    }

    /// 获取本地时间基于utc的偏移量
    pub fn offset(&self) -> (i8, i8, i8) {
        self.0.offset().as_hms()
    }

    /// 设置本地时间的基于utc的偏移量
    pub fn to_offset(&self, hours: i8, minutes: i8, seconds: i8) -> Self {
        Self(self.0.to_offset(UtcOffset::from_hms(hours, minutes, seconds).unwrap()))
    }

    /// 获取日期
    pub fn date(&self) -> LocalDate {
        self.0.date()
    }

    /// 获取时间
    pub fn time(&self) -> LocalTime {
        self.0.time()
    }

    /// 格式化日期时间
    pub fn format(&self, format: &(impl Formattable + ?Sized)) ->Result<String, Format> {
        self.0.format(format)
    }

    /// 格式化日期时间
    pub fn format_with_fmt(&self, format: &str) ->Result<String, Box<dyn Error>> {
        let desc = time::format_description::parse(format)?;
        Ok(self.0.format(&desc)?)
    }

    /// 解析时间的文本串成本地时间
    pub fn parse(input: &str) -> Result<Self, TimeParseError> {
        Ok(Self(parse_datetime(input)?))
    }

    /// 解析日期时间字符串
    pub fn parse_with(input: &str, description: &(impl Parsable + ?Sized)) -> Result<Self, TimeParseError> {
        OffsetDateTime::parse(input, description).map(|v| Self(v))
    }

    pub fn parse_with_fmt(input: &str, format: &str) -> Result<Self, Box<dyn Error>> {
        let desc = time::format_description::parse(format)?;
        Ok(Self(OffsetDateTime::parse(input, &desc)?))
    }

}

impl Default for LocalDateTime {
    fn default() -> Self {
        Self(OffsetDateTime::from_unix_timestamp(0).unwrap())
    }
}

impl Display for LocalDateTime {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self.0.format(DATETIME_FORMAT) {
            Ok(s) => {
                f.write_str(&s)?;
                Ok(())
            }
            Err(_) => Err(std::fmt::Error),
        }
    }
}

impl PartialOrd for LocalDateTime {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        self.0.partial_cmp(&other.0)
    }
}

impl Ord for LocalDateTime {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.0.cmp(&other.0)
    }
}

impl Hash for LocalDateTime {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        self.0.hash(state);
    }
}

impl Add<std::time::Duration> for LocalDateTime {
    type Output = Self;

    fn add(self, duration: std::time::Duration) -> Self::Output {
        Self(self.0.add(duration))
    }
}

impl Sub for LocalDateTime {
    type Output = time::Duration;

    fn sub(self, rhs: Self) -> Self::Output {
        self.0 - rhs.0
    }
}

impl Sub<time::Duration> for LocalDateTime {
    type Output = Self;

    fn sub(self, rhs: time::Duration) -> Self::Output {
        Self(self.0 - rhs)
    }
}

impl Sub<Duration> for LocalDateTime {
    type Output = Self;

    fn sub(self, duration: Duration) -> Self::Output {
        Self(self.0.sub(duration))
    }
}

impl AsRef<OffsetDateTime> for LocalDateTime {
    fn as_ref(&self) -> &OffsetDateTime {
        &self.0
    }
}

impl AsMut<OffsetDateTime> for LocalDateTime {
    fn as_mut(&mut self) -> &mut OffsetDateTime {
        &mut self.0
    }
}

impl From<OffsetDateTime> for LocalDateTime {
    fn from(value: OffsetDateTime) -> Self {
        LocalDateTime(value)
    }
}

impl From<PrimitiveDateTime> for LocalDateTime {
    fn from(value: PrimitiveDateTime) -> Self {
        LocalDateTime(value.assume_offset(LOCAL_OFFSET.clone()))
    }
}

impl From<SystemTime> for LocalDateTime {
    fn from(value: SystemTime) -> Self {
        LocalDateTime(OffsetDateTime::from(value).to_offset(LOCAL_OFFSET.clone()))
    }
}

impl FromStr for LocalDateTime {
    type Err = TimeParseError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        parse_datetime(s).map(|v| Self(v))
    }
}

impl Serialize for LocalDateTime {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> {
        serializer.serialize_str(&self.to_string())
    }
}

impl <'de> Deserialize<'de> for LocalDateTime {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error> {
        deserializer.deserialize_str(LocalTimeVisitor) // 为 Deserializer 提供 Visitor
    }
}

struct LocalTimeVisitor; // LocalDateTime 的 Visitor，用来反序列化

impl <'de> Visitor<'de> for LocalTimeVisitor {
    type Value = LocalDateTime; // Visitor 的类型参数，这里我们需要反序列化的最终目标是 LocalDateTime

    // 必须重写的函数，用于为预期之外的类型提供错误信息
    fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
        formatter.write_str("")
    }

    // 从字符串中反序列化
    fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
        match parse_datetime(v) {
            Ok(t) => Ok(LocalDateTime(t)),
            Err(_) => Err(E::invalid_value(Unexpected::Str(v), &self)),
        }
    }
}

#[cfg(feature = "mysql_common")]
use mysql_common::value::{Value, convert::{FromValue, ParseIr}};

#[cfg(feature = "mysql_common")]
impl From<ParseIr<PrimitiveDateTime>> for LocalDateTime {
    fn from(value: ParseIr<PrimitiveDateTime>) -> Self {
        value.commit().into()
    }
}

#[cfg(feature = "mysql_common")]
impl FromValue for LocalDateTime {
    type Intermediate = ParseIr<PrimitiveDateTime>;
}

#[cfg(feature = "mysql_common")]
impl From<LocalDateTime> for Value {
    fn from(value: LocalDateTime) -> Self {
        Value::Date(value.0.year() as u16, value.0.month().into(), value.0.day(),
        value.0.hour(), value.0.minute(), value.0.second(), value.0.microsecond())
    }
}
